package model;

import java.io.Serializable;
import java.net.UnknownHostException;
import java.util.ArrayList;

import org.workplicity.entry.Entry;
import org.workplicity.util.Helper;
import org.workplicity.util.WorkDate;
import org.workplicity.worklet.WorkletContext;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.util.JSON;

import cc.test.bridge.BridgeConstants.Side;
import cc.test.bridge.BridgeConstants.State;
import cc.test.bridge.BridgeInterface;
import cc.test.bridge.BudgetInterface;
import cc.test.bridge.LineInterface;
import cc.test.bridge.NoteInterface;


public class Budget extends Entry implements BudgetInterface
{
	public enum Roll { DAILY, BIWEEKLY, WEEKLY, BIMONTHLY, MONTHLY, BIANNUALLY, QUARTERLY, ANNUALLY };
	public enum Status { DRAFT, REVIEW, FINAL };
	protected Integer budgetId = 0;
	protected String title = "N/A";
	protected String description = "N/A";
	protected ArrayList<Integer> lineIds = new ArrayList<Integer>();
	protected ArrayList<NoteInterface> notes = new ArrayList<NoteInterface>();
	protected WorkDate startDate = new WorkDate();
	protected WorkDate endDate = new WorkDate();
	protected Roll roll = Roll.WEEKLY;
	private final String repositoryName = "Budgets";
	private static final long serialVersionUID = 1L;
	protected Status status = Status.DRAFT;
	
	public Budget()
	{
		BridgeHelper.getHamper().put(this, State.CREATE);
		
	}
	
	@Override
	public Boolean commit()
	{
		 // Commit the line and note changes
        Boolean successful = true;
        for(BridgeInterface bridge : BridgeHelper.getHamper().keySet()) { 
            // We don't commit the budget as we may have to commit
            // first commit its constituents.
            if(bridge == this)
                continue;
            
            // Commit the constituents
            State state = BridgeHelper.getHamper().get(bridge);
            if(!(bridge instanceof Budget)){
            	if(state == State.CREATE)
            		successful = commitCreate(bridge);
            
            	else if(state == State.UPDATE)
            		successful = commitUpdate(bridge);
            
            	else if(state == State.DELETE)
            		successful = commitDelete(bridge);
            
            	if(!successful){
            		System.out.println("Budget commit Failed");
            		return false;
            	}
            }
                
        }
        
        Boolean dirty = BridgeHelper.getHamper().containsKey(this);
        
        
        if(!dirty)
            return true;
        
        // If the budget itself is dirty, write it through
//        Mongo mongo = null;
//		try
//		{
//			mongo = new Mongo();
//		} catch (UnknownHostException e)
//		{
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		} catch (MongoException e)
//		{
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		
//        DB db = mongo.getDB("cc");
//        DBCollection collection = db.getCollection(this.REPOS_NAME);
//        collection.insert(new BasicDBObject().append("entry", this));
        successful = Helper.insert(this, "Budgets", WorkletContext.getInstance() );   
        
        // (Re)set the dirty state of the budget
        
        if(!successful){
            return false;
        }
        // Clear out the hamper since we just committed the bridges
        BridgeHelper.getHamper().clear();        
                    
        return true;
    }
	
	
    
    /**
     * Commits creational changes.
     * @param bridge Bridge
     * @return 
     */
    protected Boolean commitCreate(BridgeInterface bridge) {
        // Commit the interface first since we may need the unique id
        if(!bridge.commit()){
        	System.out.println("Commit Failed at budget commitCreate");
        	return false;
        }
            
        
        // Add the line or note to the budget
        if (bridge instanceof LineInterface) {
            Line line = (Line) bridge;
            if(!line.isSubline)
            	this.lineIds.add(line.getId());

        }
        else if (bridge instanceof NoteInterface) {
            notes.add((Note) bridge);
            
        }
        
        BridgeHelper.getHamper().put(this,State.CREATE);


        return true;
    }
    
    /**
     * Commits update changes.
     * @param bridge Bridge
     * @return True if the commit is successful, false otherwise
     */
    protected Boolean commitUpdate(BridgeInterface bridge) {
        return bridge.commit();
    }  
    
    /**
     * Commits the delete changes.
     * @param bridge Bridge
     * @return True if the commit is successful, false otherwise
     */
    protected Boolean commitDelete(BridgeInterface bridge) {
 
        if (bridge instanceof LineInterface) {
            Line line = (Line) bridge;
            Integer garbage = -1;

            for (Integer lineId : lineIds) {
                if (lineId.equals(line.getId()) && !line.isSubline) {
                    garbage = lineId;

                    break;
                }
            }

            if (garbage != -1) {
            	lineIds.remove(garbage);
            }

            
        } else if (bridge instanceof NoteInterface) {
            notes.remove(bridge);
        }

       

        return bridge.commit();
    } 
	
	@Override
	public String getName()
	{
		return this.title;
	}
	
	@Override
	public void setName(String arg0)
	{
		this.title = arg0;
		
		BridgeHelper.getHamper().put(this, State.UPDATE);
	}
	
	@Override
	public void add(NoteInterface note)
	{
		this.notes.add(note);
		
        BridgeHelper.getHamper().put(this, State.UPDATE);
	}
	
	@Override
	public void add(LineInterface line)
	{
		BridgeHelper.getHamper().put(line, State.CREATE);
        
        BridgeHelper.getHamper().put(this, State.UPDATE);

	}
	
	@Override
	public LineInterface createLine()
	{
		return new Line(this.id);
	}
	
	@Override
	public NoteInterface createNote()
	{
		return new Note();
	}
	
	@Override
	public void delete(NoteInterface note)
	{
		this.notes.remove(note);
        
        BridgeHelper.getHamper().put(this, State.UPDATE);
		
	}
	
	@Override
	public void delete(LineInterface line)
	{
		BridgeHelper.getHamper().put(line, State.DELETE);
        
        BridgeHelper.getHamper().put(this, State.UPDATE);
		
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public ArrayList<LineInterface> fetchLines(Side side)
	{
		
		BasicDBObject predicate = new BasicDBObject();

		predicate.put("entry.budgetId", this.id);
		
		String criteria = JSON.serialize(predicate);
		
		ArrayList<LineInterface> lines = Helper.query(criteria, WorkletContext.getInstance());
		
		return lines;
	}
	
	@Override
	public ArrayList<NoteInterface> fetchNotes()
	{
		return this.notes;
	}
	
	@Override
	public String getDescription()
	{
		return this.description;
	}
	
	@Override
	public void setDescription(String des)
	{
		this.description = des;
		BridgeHelper.getHamper().put(this, State.UPDATE);
	}
	
	@Override
	public void update(LineInterface line)
	{
		BridgeHelper.getHamper().put(line, State.UPDATE);
        
        BridgeHelper.getHamper().put(this, State.UPDATE);
	}
	
	@Override
	public void update(NoteInterface note)
	{
		BridgeHelper.getHamper().put(note, State.UPDATE);
        
        BridgeHelper.getHamper().put(this, State.UPDATE); 
	}
	
	public ArrayList<Integer> getLineIds()
	{
        return lineIds;
    }

    public void setLineIds(ArrayList<Integer> lineIds)
    {
        this.lineIds = lineIds;
        
        BridgeHelper.getHamper().put(this, State.UPDATE);         
    }
	
	public WorkDate getEndDate()
	{
        return endDate;
    }

    public void setEndDate(WorkDate endDate)
    {
        this.endDate = endDate;
        
        BridgeHelper.getHamper().put(this, State.UPDATE);        
    }
    
    public WorkDate getStartDate()
    {
        return startDate;
    }

    public void setStartDate(WorkDate startDate)
    {
        this.startDate = startDate;
        
        BridgeHelper.getHamper().put(this, State.UPDATE);        
    }
    
    public ArrayList<NoteInterface> getNotes()
    {
        return notes;
    }

    public void setNotes(ArrayList<NoteInterface> notes)
    {
        this.notes = notes;
        
        BridgeHelper.getHamper().put(this, State.UPDATE);         
    }

    public Roll getRoll()
    {
        return roll;
    }

    public void setRoll(Roll roll)
    {
        this.roll = roll;
        
        BridgeHelper.getHamper().put(this,State.UPDATE);
    }
    
	@Override
	public String getRepositoryName()
	{
		return repositoryName;
	}
	
	public void setRepositoryName(String name)
	{
		
	}
	
	public Status getStatus()
	{
		return status;
	}

	public void setStatus(Status status)
	{
		this.status = status;
	}
}
